// hookexe.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"
#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>
#include <atlstr.h>
#include <shellapi.h>
#include "Hooks.h"
#include "Logging.h"
#include <WinUser.h>

#define MAX_LOADSTRING 100

typedef void (__stdcall *pFunc)(void);				//function pointer to call sethook and removehook functions

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];								// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];	
WNDPROC g_OrigWndProc;
// The title bar text

// Foward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

enum
{
	CMD_NONE = -1,
	CMD_TOGGLE_NEW = -2,
};

const int WM_OPEN = WM_USER + 10;
const int TIMER_CHECK_TASKBAR_MOVED = 4;
const int TIMER_CHECK_HEARTBEAT = 3;
const int TIMER_CLOSE_POPUP_WINDOW = 2;
const int TIMER_CHECK_EXPLORER_RUNNING = 1;
long g_LastCallerTime = 0;
int open = CMD_NONE;
HWND g_ProgWin = NULL;

enum TMenuMsgParam // wParam for the ClassicStartMenu.StartMenuMsg message
{
	MSG_TOGGLE, // toggles the classic start menu
	MSG_OPEN, // opens the classic start menu
	MSG_SETTINGS, // show Settings
	MSG_SHIFTWIN, // Shift+Win was pressed
	MSG_DRAG, // an item is dragged on the start button
	MSG_SHIFTDRAG, // an item is dragged on the start button (Shift is pressed)
	MSG_FINDMENU, // find Windows menu
	MSG_EXIT, // unhook everything and exit
	MSG_HOTKEYS, // updates the hotkeys
};

static UINT g_TaskbarCreatedMsg; // the "TaskbarCreated" message
int g_BMO, g_BKO, g_SBMO, g_SBKO, g_MBMO, g_TMBMO, g_DMS, g_DHE, g_RAFG, g_CMO, g_CLSO;
bool g_bReplaceButton, g_bReplaceAllTaskbars;
bool g_bCallerIsVisible = false;
LPWSTR *g_SBS, *g_TranslationsPath, *g_CmdLoggingPath;
static HWND g_CallerHandle;



class CWinKStartHookWindow : public CWindowImpl<CWinKStartHookWindow>
{
public:

	DECLARE_WND_CLASS("WinKStart.CWinKStartManagement")

	BEGIN_MSG_MAP(CWinKStartHookWindow)
		MESSAGE_HANDLER(WM_OPEN, OnOpen)
		MESSAGE_HANDLER(WM_CLOSE, OnClose)
		MESSAGE_HANDLER(WM_CLEAR, OnClear)
		MESSAGE_HANDLER(WM_TIMER, OnTimer)
		MESSAGE_HANDLER(g_TaskbarCreatedMsg, OnTaskbarCreated)
	END_MSG_MAP()

protected:
	// Handler prototypes:
	//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
	//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
	LRESULT OnOpen(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnClear(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnTaskbarCreated(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
};

LRESULT CWinKStartHookWindow::OnOpen(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{	
	g_ProgWin = FindWindowExW(NULL, NULL, L"Progman", NULL);

	if (g_ProgWin) {
		//Set StartButton Options
		SetOptions(g_BMO, g_BKO, g_SBMO, g_SBKO, g_MBMO, g_TMBMO, g_SBS, g_DMS, g_DHE, g_RAFG, 
				   g_CMO, g_bReplaceButton, g_bReplaceAllTaskbars, g_TranslationsPath, 
				   g_CmdLoggingPath, g_CLSO);
		//Init StartMenu Button
		InitButton();
	}
	
	SetTimer(TIMER_CHECK_EXPLORER_RUNNING, 1000);
	SetTimer(TIMER_CHECK_TASKBAR_MOVED, 100);
return 0;
}

int TimesWithNoLiveSign = 0;

LRESULT CWinKStartHookWindow::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	CloseButton();
	SendMessageW(g_CallerHandle, WM_ACTION_WINKSTART_CLOSE, 0, 0);
	Sleep(100);
	PostQuitMessage(0);
	return 0;
}

LRESULT CWinKStartHookWindow::OnClear(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	//CloseStartMenu();
	return 0;
}

LRESULT CWinKStartHookWindow::OnTaskbarCreated(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	//LogMessage("WM_TaskBarCreated", LOG_DEBUG);
	//SetTimer(TIMER_HOOK, 100);
	return 0;
}

LRESULT CWinKStartHookWindow::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	if (wParam == TIMER_CHECK_EXPLORER_RUNNING)
	{
		HWND tmpProgMan = FindWindowExW(NULL, NULL, L"Progman", NULL);

		if (!tmpProgMan && g_ProgWin) {
			g_bCallerIsVisible = false;
			SendMessageW(g_CallerHandle, WM_ACTION_WINKSTART_HIDE, 0, 0);
			//Explorer was terminated
			g_ProgWin = NULL;
			CloseButton();
		}
		else if (tmpProgMan && !g_ProgWin) {
			//Explorer was started
			g_ProgWin = tmpProgMan;
			//Init StartMenu Button
			InitButton();
		}
		//Test Heartbeat
		time_t t;
		time(&t);

		SendMessageW(g_CallerHandle, WM_ACTION_BTN_ASK_GUI_LIVES, 0, 0);
		TimesWithNoLiveSign += 1;

		//if (g_LastCallerTime + g_RAFG < t){
		if (TimesWithNoLiveSign > g_RAFG + 2){
			CloseButton();
			Sleep(100);
			PostQuitMessage(0);
		}
	}
	else if (wParam == TIMER_CLOSE_POPUP_WINDOW)
	{
		CloseButton();
		Sleep(100);
		PostQuitMessage(0);
	}
	else if (wParam == TIMER_CHECK_HEARTBEAT) {
		SendMessageW(g_CallerHandle, WM_ACTION_BTN_ASK_GUI_LIVES, 0, 0);
		TimesWithNoLiveSign += 1;
		//time_t t;
		//time(&t);

		//if (g_LastCallerTime + g_RAFG < t){
		if (TimesWithNoLiveSign > g_RAFG + 2){
			CloseButton();
			Sleep(100);
			PostQuitMessage(0);
		}
	}
	else if (wParam == TIMER_CHECK_TASKBAR_MOVED) {
		HasMovedTaskbar();
	}
	return 0;
}

static LRESULT CALLBACK SubclassManagerWindow(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
	//if (uMsg == WM_OPEN)
	//	g_RAFG = 30;
	if (uMsg == WM_ACTION_STARTMENU){
		LogMessage("Activate/Deactivate WinKStart", LOG_ACTIONS);
		if (!g_bCallerIsVisible) {
			g_bCallerIsVisible = true;
			int ircStartMenuStartPos = 0;
			RECT rcStartMenu;

			GetWindowRect(g_CallerHandle, &rcStartMenu);

			//Get StartPosition
			if (lParam != NULL && lParam > 0)
				ircStartMenuStartPos = lParam;

			int iLeftPos = 0;
			int iTopPos = 0;

			if (ircStartMenuStartPos > 0) {
				iLeftPos = LOWORD(ircStartMenuStartPos);
				iTopPos = HIWORD(ircStartMenuStartPos);
			}

			if (wParam == 2){
				//right Pos
				iLeftPos = iLeftPos - (rcStartMenu.right - rcStartMenu.left);
			}
			else if (wParam == 3) {
				iTopPos = iTopPos - (rcStartMenu.bottom - rcStartMenu.top);
			}
			
			//Set Window Position
			SetWindowPos(g_CallerHandle, HWND_TOPMOST, iLeftPos, iTopPos, 0, 0, SWP_NOSIZE);
			SendMessageW(g_CallerHandle, WM_ACTION_WINKSTART_SHOW, 0, 0);
		}
		else {
			g_bCallerIsVisible = false;
			SendMessageW(g_CallerHandle, WM_ACTION_WINKSTART_HIDE, 0, 0);
		}
	}
	else if (uMsg == WM_ACTION_SET_CALLER) {
		g_CallerHandle = (HWND)lParam;
		//Save timestamp from last heartbeat
		time_t t;
		time(&t);
		g_LastCallerTime = t;

		//LogMessage("WM_ACTION_SET_CALLER", g_CallerHandle, LOG_ACTIONS);
	}
	else if (uMsg == WM_ACTION_OPENSETTINGSDLG) {
		SendMessageW(g_CallerHandle, WM_ACTION_OPENSETTINGSDLG, 0, 0);
	}
	else if (uMsg == WM_ACTION_WINKSTART_HIDE) 
	{
		g_bCallerIsVisible = false;
		SendMessageW(g_CallerHandle, WM_ACTION_WINKSTART_HIDE, 0, 0);
	}
	else if (uMsg == WM_ACTION_WINKSTART_NOTIFY_HIDDEN)
		g_bCallerIsVisible = false;
	else if (uMsg == WM_ACTION_TEST_VALUE){
		LogMessage("Received Test Value: ", (int)lParam, LOG_ACTIONS);
	}
	else if (uMsg == WM_ACTION_BTN_ASK_GUI_LIVES){
		TimesWithNoLiveSign = 0;
	}
	return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	


 	// TODO: Place code here.
	MSG msg;
	LPWSTR *szArglist;
	int nArgs;

	//Read the Arguments
	szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
	//szArglist[1] //BMO - Button Mouse Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
	//szArglist[2] //BKO - Button Key Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
	//szArglist[3] //SBMO - Shift Button Mouse Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
	//szArglist[4] //SBKO - Shift Button Key Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
	//szArglist[5] //MBMO - Move Button Mouse Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
	//szArglist[6] //TMBMO - Delay-time MBMO Example 100 
	//szArglist[7] //SBS - Start Button Symbol (Path for Windows Bitmap Image)
	//szArglist[8] //DMS - Disable Metro Screen (0 - Disable, 1 - Enable)
	//szArglist[9] //DHE - Disable Hot Edges (0 - Disable, 1 - Enable)
	//szArglist[10] //RAFG - Restore After Failed GUI in Seconds (Example 30) 
	//szArglist[11] //CMO - Context Menu Options (67 for Example)
	if (nArgs == 17)
	{
		//Argument BMO - Button Mouse Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
		g_BMO = _wtoi(szArglist[1]);
		//Argument BKO - Button Key Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
		g_BKO = _wtoi(szArglist[2]);
		//Argument SBMO - Shift Button Mouse Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
		g_SBMO = _wtoi(szArglist[3]);
		//Argument SBKO - Shift Button Key Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
		g_SBKO = _wtoi(szArglist[4]);
		//Argument MBMO - Move Button Mouse Open (0 - Nothing, 1 - WinKStart, 2 - Metro)
		g_MBMO = _wtoi(szArglist[5]);
		//Argument TMBMO - Delay-time MBMO Example 100 
		g_TMBMO = _wtoi(szArglist[6]);
		//Argument SBS - Start Button Symbol (Path for Windows Bitmap Image)
		g_SBS = &szArglist[7];
		//Argument DMS - Disable Metro Screen (0 - Disable, 1 - Enable)
		g_DMS = _wtoi(szArglist[8]);
		//Argument DHE - Disable Hot Edges (0 - Disable, 1 - Enable)
		g_DHE = _wtoi(szArglist[9]);
		//Argument RAFG - Restore After Failed GUI in Seconds (Example 30) 
		g_RAFG = _wtoi(szArglist[10]);
		//Argument CMO - Context Menu Options (67 for Example)
		g_CMO = _wtoi(szArglist[11]);
		//Argument CLSO
		g_CLSO = _wtoi(szArglist[12]);
		//Argument ReplaceButton
		g_bReplaceButton = (_wtoi(szArglist[13]) == 1);
		//Argument ReplaceAllTaskbars
		g_bReplaceAllTaskbars = (_wtoi(szArglist[14]) == 1);
		//Argument Path to Translation files (GetText)
		g_TranslationsPath = &szArglist[15];
		//Logging Path+ Filename
		g_CmdLoggingPath = &szArglist[16];
		//TODO: reading Log off Shutdown ContextMenu Items settings

		LogMessage("Load Parameters successfull.", LOG_ACTIONS);
		//1 1 2  2 0 100 images\ownwinkstart96.bmp  0 1 60 2097151 1 1 D:\matthias\downloads\hookSrc\hookSrc\debug\languages
	}
	else
	{
		LogMessage("Load Parameters Failed!", LOG_ACTIONS);
		LogMessage("Not enought Parameters!", LOG_ACTIONS);
		LogMessage("Process can't execute!", LOG_ACTIONS);
		//not all needed arguments given,
		//fire an exception
		return 0;
	}

	//Check if an instance from startbutton is already loaded
	HWND hStartButton = FindWindowExW(NULL, NULL, L"WinKStart.CWinKStartManagement", NULL);	
	if (hStartButton) return -1;

	//Create a window used to "life" the function
	CWinKStartHookWindow HookWindow;
	//WinKStart.CWinKStartHookWindow
	HookWindow.Create(NULL, NULL, "CWinKStartManagement", WS_POPUP);

	//send message to open the WinKStartHookWindow
	HookWindow.PostMessage(WM_OPEN, open, MSG_OPEN);

	SetWindowSubclass(HookWindow, SubclassManagerWindow, 'CLSH', 0);
	//Set initial heartbeat
	time_t t;
	time(&t);
	g_LastCallerTime = t;

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	RemoveWindowSubclass(HookWindow, SubclassManagerWindow, 'CLSH');
	//after Window is no longer needed, Destroy it
	HookWindow.DestroyWindow();

	return msg.wParam;
}


